﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LGPeWJNM.BaseClasses;

namespace LGPeWJNM.Vmp
{
    /// <summary>
    /// Método de designação por vizinho mais próximo
    /// </summary>
    public class Vmp : IRoteirizacao
    {
        /// <summary>
        /// Ordena os agrupamentos de clientes a fim de minimizar os trajetos entre eles em seus grupos
        /// </summary>
        /// <remarks>Implementado através do critério de <i>vizinho mais próximo</i></remarks>
        /// <param name="destinos">Conjunto de grupos desordenados de coordenadas de destinos</param>
        /// <param name="deposito">Coordenadas do depósito</param>
        /// <param name="quantidadeVeiculos">Número de veículos disponíveis para a roteirização</param>
        /// <param name="capacidadeVeiculo">Capacidade de carga de cada veículo</param>
        /// <returns>Conjunto de grupos ORDENADOS de coordenadas de destinos</returns>
        public IEnumerable<LinkedList<ICliente>> Processar(IEnumerable<IEnumerable<ICliente>> destinos, Point deposito, int quantidadeVeiculos, float capacidadeVeiculo)
        {
            //var resp = new LinkedList<ICliente>[destinos.Count()];
            //System.Threading.Tasks.Parallel.For(0, destinos.Count(), i =>
            //{
            //    resp[i] = processaCadaCluster(destinos.ElementAt(i), deposito);
            //});
            //return resp;
            foreach (var cluster in destinos)
            {
                yield return processaCadaCluster(cluster, deposito);
            }
        }

        private LinkedList<ICliente> processaCadaCluster(IEnumerable<ICliente> cluster, Point deposito)
        {
            var clientesRestantes = new List<ICliente>(cluster);
            var trechos = new LinkedList<ICliente>();
            trechos.AddFirst(new Cliente() { Coordenada = deposito, Demanda = 0, Id = 1 });
            while (clientesRestantes.Count > 0)
            {
                var proximoNo = (from c1 in clientesRestantes
                                 orderby c1.Coordenada % trechos.Last.Value.Coordenada
                                 select c1).First();
                trechos.AddLast(proximoNo);
                clientesRestantes.Remove(proximoNo);
            }
            trechos.AddLast(new Cliente() { Coordenada = deposito, Demanda = 0, Id = 1 });
            return trechos;
        }
    }
}
